package simulation;

import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * 学生类
 * 记录当前学生处于哪一个路径和空间
 * 记录学生感染状态：健康、被感染、有症状、死亡
 * 记录路径表
 * 走路
 * TODO：实现隔离区
 */
public class Student extends Circle {
    private final int type; // 学生类型
    private final int[] classrooms = new int[] { MathUtil.randomInt(10, 15), MathUtil.randomInt(10, 15), MathUtil.randomInt(10, 15) };
    private final int[] canteens = new int[] { MathUtil.randomInt(16, 18), MathUtil.randomInt(16, 18), MathUtil.randomInt(16, 18) };
    private int currSpace; // 当前所在空间
    private ArrayList<Path> paths; // F路径表
    private int pathIndex = 0;
    //感染相关
    private State state = State.HEALTHY; // 学生状态
    private int stateCounter;//感染后发病计数器和发病后康复计数器
    private Path[] toQuarantine = new Path[3];
    private boolean hadQuarantine = false;
    private int[] toQuarantineIndex = new int[]{0,0,0};
    //move相关内容
    private Path currPath; // 当前进行的一小段路径
    //private int count = 0;
    private int countStart ;
    private int countEnd;
    private double speedX;
    private double speedY;

    public Student(int type) {
        this.type = type;
        initPath(); // 初始化路径表

        currSpace = paths.get(0).getStartSpace(); // 获取出生位置
        Map.getSpaces().get(currSpace).addStudent(this);//将学生加入space的链表
        // 初始化圆
        setCenterX(Map.getSpaces().get(currSpace).getRandomX());
        setCenterY(Map.getSpaces().get(currSpace).getRandomY());
        setRadius(GlobalVar.RADIUS);
        setFill(getColor(state));

//        System.out.println("On init: ");
//        System.out.println("centerX = " + this.getCenterX() + "  centerY = " + this.getCenterY());

    }

    /**
     * 获取状态对应的颜色
     * @param s 学生之状态
     * @return 代表学生的圆之颜色
     */
    public static Color getColor(State s) {
        return switch (s) {
            case HEALTHY -> Color.LIGHTGREEN;
            case INFECTED -> Color.YELLOW;
            case SYMPTOMATIC -> Color.RED;
        };
    }
    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
        this.setFill(getColor(state));
    }
    /**
     * 走路函数
     * 在此函数中更改this.centerX和this.centerY以实现移动之效果
     * 实现更改space对应的学生链表
     * TODO：走的不对
     */
    public void move() {
        DecimalFormat df = new DecimalFormat("0.0#");
        if(countEnd + countStart == 0) {
            changePath();
        }
        if (currSpace == currPath.getEndSpace()) {
            //随机移动
            double x = 0,y =0;
            while (!Map.getSpaces().get(currSpace).inSpace(x,y)) {
                x = MathUtil.stdGaussian(GlobalVar.ONE_STEP, this.getCenterX());
                y = MathUtil.stdGaussian(GlobalVar.ONE_STEP, this.getCenterY());
            }
            this.setCenterX(x);
            this.setCenterY(y);
            countStart--;
        }
        else if (currSpace == 19) {    // 如果目的地是操场则会到达操场后卡在第一个随机移动，不会进入这个函数
            //在操场，移动到endSpace
            if (countEnd == 1) {//修改链表
                Map.getSpaces().get(currSpace).deleteStudent(this);
                currSpace = currPath.getEndSpace();
                Map.getSpaces().get(currSpace).addStudent(this);
            }
            else {
                this.setCenterX(this.getCenterX() + speedX);
                this.setCenterY(this.getCenterY() + speedY);
            }
            countEnd--;
        }
        else {
            //初始位置，移动到操场
            if (countStart == 1) {//修改链表
                if(currSpace == 20) setFill(getColor(State.HEALTHY));
                Map.getSpaces().get(currSpace).deleteStudent(this);
                currSpace = 19;
                Map.getSpaces().get(currSpace).addStudent(this);
                changeSpeed();
            }
            else {
                this.setCenterX(this.getCenterX() + speedX);
                this.setCenterY(this.getCenterY() + speedY);
            }
            countStart--;
        }
    }

    private void changePath() {
        if (++ pathIndex >= paths.size() || GlobalVar.TIME % 2000 == 0) {
            pathIndex = 0;
        }
        currPath = paths.get(pathIndex);
        countStart = currPath.getCountStart();
        countEnd = currPath.getCountGround();
        changeSpeed();
    }

    private void changeSpeed() {
        if (currSpace == 19 && currPath.getEndSpace() != 19) {
            //操场移动到结束位置
            Position end = Map.getSpaces().get(currPath.getEndSpace()).getDoor().getRandomPos();
            speedX = MathUtil.getSpeed(this.getCenterX(), end.getX(), countEnd -1 );
            speedY = MathUtil.getSpeed(this.getCenterY(), end.getY(), countEnd -1 );
        }
        else if (currSpace != 19 && currSpace != currPath.getEndSpace()) {
            //初始位置，移动到通向操场的门
            // TODO: debug
            //if(countStart == 0) {System.out.println("you bug"); countStart++;}
            speedX = MathUtil.getSpeed(this.getCenterX(),
                    Map.getSpaces().get(currPath.getStartSpace()).getDoor().getRandomPos().getX(),
                    countStart-1);
            speedY = MathUtil.getSpeed(this.getCenterY(),
                    Map.getSpaces().get(currPath.getStartSpace()).getDoor().getRandomPos().getY(),
                    countStart-1);
        }
    }
    /**
     * 该学生路径表的初始化函数
     */
    private void initPath() {
        // 根据用Timetable.getTimePoints(type)获得的时间点，给this.paths里面的每一个path：
        // 1）具体化startSpace和endSpace并计算时间片长度和计数器
        // 2）调用path.setTimeSlice()，path.setCount()来设置时间片和计数器
        // 3）别忘了调用GlobalVar.PLAYBACK_SPEED来计算
        int dorm = MathUtil.randomInt(0, 9);
        this.paths = new ArrayList<>();
        for (Path p : Timetable.getPaths(type)) {
            this.paths.add(p.clone());
        }

        // 设置startSpace, endSpace
        int classroomCount = 0, canteenCount = 0;
        for (Path path : paths) {
            switch (path.getStartSpace()) {
                case 0 -> path.setStartSpace(dorm);
                case 10 -> {
                    path.setStartSpace(classrooms[classroomCount / 4]);
                    classroomCount++;
                }
                case 16 -> {
                    path.setStartSpace(canteens[canteenCount / 4]);
                    canteenCount++;
                }
            }
            switch (path.getEndSpace()) {
                case 0 -> path.setEndSpace(dorm);
                case 10 -> {
                    path.setEndSpace(classrooms[classroomCount / 4]);
                    classroomCount++;
                }
                case 16 -> {
                    path.setEndSpace(canteens[canteenCount / 4]);
                    canteenCount++;
                }
            }
        }
        // 设置timeSlice
        // 使用了高斯分布，模拟大多数同学都准时行动
        int prev = 0, bias = 0;
        for (int i = 0; i < paths.size(); i++) {
            // TODO: debug
            int _timeSlice = (Timetable.getTimePoints(type).get(i) - prev) * 20;

            if (i % 2 == 0) {
                bias = (int) MathUtil.stdGaussian((double) 10, _timeSlice) - _timeSlice;
                _timeSlice += bias;
            }
            else {
                _timeSlice -= bias;
            }
            paths.get(i).setTimeSlice(_timeSlice);
            prev = Timetable.getTimePoints(type).get(i);
        }
        /*// TODO: 删除debug
        int total = 0;
        for (Path p : paths)
            total += p.getTimeSlice();
        System.out.println("Total time slice = " + total);
        */
        pathIndex = -1;
    }

    public void toRecover() {
        boolean flag = true;
        if(--stateCounter == 0){
            setState(State.HEALTHY);
            if(GlobalVar.QUARANTINE && hadQuarantine){
                GlobalVar.NUM_QUARANTINE--;
                hadQuarantine = false;
                if(pathIndex + 1 == paths.size()){
                    System.out.println("最后一个时间段被感染");
                }
                if((toQuarantineIndex[2] + 1)% paths.size() != pathIndex){
                    System.out.println("121112312");
                }
                for (int i = 0; i < 3; i++) {
                    paths.remove(toQuarantine[i]);
                    if (pathIndex == toQuarantineIndex[i]) {
                        System.out.println("BUG in Recover  " + i);
                        if( i == 0 )flag = false;
                    }

                }
                if(flag) if(pathIndex >= 3) pathIndex -= 3;

            }
        }
    }
    public void toSymptomatic() {
        if (--stateCounter == 0) {
            this.setState(State.SYMPTOMATIC);
            stateCounter = (int) (GlobalVar.DAYS_TO_RECOVER * GlobalVar.ONE_DAY);
            if(GlobalVar.QUARANTINE && GlobalVar.NUM_QUARANTINE < GlobalVar.MAX_QUARANTINE ) {
                GlobalVar.NUM_QUARANTINE++;
                hadQuarantine = true;
                paths.add(pathIndex + 1,toQuarantine[0] = new Path(currPath.getEndSpace(),20, 20));
                paths.add(pathIndex + 2,toQuarantine[1] = new Path(20,20,
                        stateCounter - (countEnd + countStart + 40) - 2));
                paths.add(pathIndex + 3 ,toQuarantine[2] = new Path(20,currPath.getEndSpace(),
                        20));
                for (int i = 1; i <= 3;i++) {
                    toQuarantineIndex[i -1] = pathIndex +i;
                }
            }
        }
    }
    public void toInfected() {
        this.setState(State.INFECTED);
        stateCounter = (int) (GlobalVar.DAYS_TO_SYMPTOMATIC * GlobalVar.ONE_DAY);
    }
}